package com.kstech.mp3604.manager.socket

import android.content.Context
import com.blankii.androidlibrary.exts.logd
import com.blankii.androidlibrary.exts.loge
import com.blankii.androidlibrary.exts.logi
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.SPUtils
import com.easysocket.EasySocket
import com.easysocket.config.EasySocketOptions
import com.easysocket.entity.SocketAddress
import com.easysocket.interfaces.conn.SocketActionListener
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.kstech.mp3604.base.Global
import com.kstech.mp3604.base.Global.ANGLE
import com.kstech.mp3604.base.Global.INNER_ARC
import com.kstech.mp3604.base.Global.ONE_LINE_LENGTH
import com.kstech.mp3604.base.Global.OUTER_ARC
import com.kstech.mp3604.base.Global.PIANCHA
import com.kstech.mp3604.base.Global.PIANCHA_Y
import com.kstech.mp3604.base.Global.TWO_LINE_LENGTH
import com.kstech.mp3604.base.HomeViewModel
import com.kstech.mp3604.bean.ConfigParam
import com.kstech.mp3604.bean.Data2
import com.kstech.mp3604.bean.Data3
import com.kstech.mp3604.bean.Data4
import com.kstech.mp3604.bean.Data6
import com.kstech.mp3604.bean.TaskData
import com.kstech.mp3604.bean.ToPdaData
import com.kstech.mp3604.data.DbManager
import com.kstech.mp3604.utils.IPUtil
import com.kstech.mp3604.utils.TimeUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONObject


/**
 * author: lenovo
 * created on: 2023/12/19 16:09
 * description:业务逻辑记录
 * 一个仓库又分多个口，1号口 2号口 3号口，只有一个原点，坐标x是连续不断的
 * 一份任务单=一个调拨单号
 * 一个调拨单号包裹多个子任务
 * 一个子任务和仓库id一致
 * 一个仓库id对应多个堆信息
 * 一个堆信息包含存储区面积
 *
 * ************发送心跳************
 * socket连接成功之后自动发送心跳
 * 每两秒发送一次
 * 应用退出发送协程结束
 * 屏幕息屏依然可以发送
 *
 *************送config请求*********
 * 当控制器请求config配置时，查询SharedPreferences，简称sp
 * 发送相应的仓库id给socket，请求config数据
 * 接收config解析并分别存储到sp对应id中
 *
 * ********设备状态*********
 * 平板初始化阶段、控制器掉线状态时      STANDBY
 * 实时重量<Global.DZ_WEIGHT时       NOLOAD
 * 实时重量>=Global.DZ_WEIGHT时      WITHLOAD
 * 控制器传来故障状态时                FAULT
 * 堆码完成发送一帧                   DM_FINISHED
 * 起吊完成发送一帧                   QD_FINISHED
 *
 *
 * ************************
 */
object SocketManager : SocketActionListener() {
    private lateinit var mSocketStatusListener: SocketStatusListener//socket 连接状态
    private lateinit var mSocketMsgListener: SocketMsgListener//socket 通讯数据
    private val TAG: String = "SocketManager"
    private val revDataStringBuilder = StringBuilder()
    var threadLive = true
    private var isHaveConfig = false //每次开机均请求一遍
    private lateinit var mHomeViewModel: HomeViewModel
    private var isOnlineCount = 3
    val ipAddress by lazy {
        IPUtil.getLocalIpAddress()
    }

    private fun sendConfig() {
        /**
         * 每次开机都会请求一次config
         */
        CoroutineScope(Dispatchers.IO).launch {
            while (threadLive) {

                if (isResume && mHomeViewModel.socketCommIsConnect.value == true && !isHaveConfig && !Global.app_wareHouse.isEmpty()) {
                    sendSocketData(
                        "config", Data6(Global.app_wareHouse)
                    )
                    "send-config".logi("服务器-发送")
                } else {
                    "send-config".logi("服务器-发送-失败")
                }
                delay(5 * 1000)
            }
        }
    }

    private var isResume = false

    /**
     * 因为应用一直不退出，所以担心不会走onCreated
     * 所以在每一次Resume的时候请求一次config
     */
    fun onResume() {
        isResume = true
        isHaveConfig = false
    }

    fun onPause() {
        isResume = false
    }

    /**
     * 当收到控制器通讯之后才发送心跳，断开串口通讯之后停止发送心跳
     * 开启心跳
     */
    private fun startHeatBeat() {
        CoroutineScope(Dispatchers.IO).launch {
            while (threadLive) {
//                if (mHomeViewModel.serialCommIsConnect) { //是否先控制器通讯，再发送心跳
                if (isResume) {
                    sendSocketData(
                        "heartbeat", Data2(
                            ipAddress,
                            0,
                            mHomeViewModel.device_posX.value!!.toInt() + PIANCHA,
                            mHomeViewModel.device_posY.value!! - PIANCHA_Y,
                            mHomeViewModel.device_posZ.value!!,
                            mHomeViewModel.device_weight.value!! * 1000,
                            mHomeViewModel.device_state.value!!.data,
                            0,
                            0
                        )
                    )
                    if (isOnlineCount >= 3) {
                        mHomeViewModel.socketCommIsConnect.postValue(false)
                    } else {
                        mHomeViewModel.socketCommIsConnect.postValue(true)
                    }
                    isOnlineCount++
                }
                delay(2000)
            }
        }
    }

    fun bindSocketMsgListener(listener: SocketMsgListener) {
        mSocketMsgListener = listener
    }

    override fun onSocketConnSuccess(socketAddress: SocketAddress?) {
        super.onSocketConnSuccess(socketAddress)
        //通讯activity socket连接成功
        mSocketStatusListener.success()
        "socket-success".logd("socket连接状态")
    }

    override fun onSocketConnFail(socketAddress: SocketAddress?, isNeedReconnect: Boolean) {
        super.onSocketConnFail(socketAddress, isNeedReconnect)
        mSocketStatusListener.fail()
        "socket-ConnFail".logd("socket连接状态")
    }

    override fun onSocketDisconnect(socketAddress: SocketAddress?, isNeedReconnect: Boolean) {
        super.onSocketDisconnect(socketAddress, isNeedReconnect)
        mSocketStatusListener.disConnect()
        "socket-success".logd("socket连接状态")
    }

    override fun onSocketResponse(socketAddress: SocketAddress?, readData: String?) {
        super.onSocketResponse(socketAddress, readData)
        isOnlineCount = 0
        /**
         * 下边的所有工作都是为了接收超长字符串
         */
//        "接收数据$readData".loge(TAG)
        try {
            //如果存在表头  清除revDataStringBuilder
            if (readData!!.contains("topic")) {
                revDataStringBuilder.clear()
            }
        } catch (e: Exception) {

        }
        revDataStringBuilder.append(readData)
        runCatching {
            //因为不知道整个json 的完整长度，revDataStringBuilder加完一条之后就过来解析试试
            val fromPdaData = JSONObject(revDataStringBuilder.toString())
            when (fromPdaData.getString("topic")) {
                "task/start" -> {
                    //socket 时间戳同步到本地
                    val timestamp = fromPdaData.getString("timestamp")
                    TimeUtil.setSocketTime(timestamp)
                    //解析data
                    val dataListByWareHouseId = ArrayList<TaskData>()
                    val data: List<TaskData> = Gson().fromJson(
                        fromPdaData.getString("data"), object : TypeToken<List<TaskData>>() {}.type
                    )
                    revDataStringBuilder.toString().logd("服务器-接收-源数据")
                    //暂时以对象形式保存在内存中
                    data.forEach {
                        //按仓库id筛选需要的数据 任务单号
                        if (Global.app_wareHouse.isBlank()) {
                            mSocketMsgListener.showEmptyWareHouseIdDialog()
                            return
                        } else if (it.warehouseId == Global.app_wareHouse) {
                            it.timestamp = TimeUtil.getDateTimeStr()
                            dataListByWareHouseId.add(it)

                            //向15所发送接收反馈  一个平板回应和他仓库id一致的
                            sendSocketData(
                                "task/start", Data3(
                                    it.transferOrderNo, 1, it.taskId
                                )
                            )
                            "仓库id：${it.warehouseId},任务单号:${it.transferOrderNo},任务id:${it.taskId}".logd(
                                "服务器-返回task/start"
                            )

                            //保存到数据库中
                            CoroutineScope(Dispatchers.IO).launch {
                                //存储到数据库
                                val result = DbManager.db.taskDataDao()
                                    .addBatchTaskData(dataListByWareHouseId)
                                withContext(Dispatchers.Main) {
                                    mSocketMsgListener.newMsg()
                                }
                            }
                        }
                    }
                }
                //easySocket 可以判断连接与断开,所以收到心跳没有处理
                "heartbeat" -> {
                    "heartbeat".loge(TAG)
                }

                "task/end" -> {
                    "task/end".loge(TAG)
                }

                "ack" -> {
                    "ack".loge(TAG)
                }
                //仓库参数，接收到之后，存到数据库，等待控制器调用，如果数据库没有弹出提示
                "config" -> {
                    isHaveConfig = true
                    val data: List<ConfigParam> = Gson().fromJson(
                        fromPdaData.getString("data"),
                        object : TypeToken<List<ConfigParam>>() {}.type
                    )
                    SPUtils.getInstance().put(ONE_LINE_LENGTH, data[0].oneLineLength)
                    SPUtils.getInstance().put(TWO_LINE_LENGTH, data[0].twoLineLength)
                    SPUtils.getInstance().put(INNER_ARC, data[0].innerArc)
                    SPUtils.getInstance().put(OUTER_ARC, data[0].outerArc)
                    SPUtils.getInstance().put(ANGLE, data[0].angle)
//                    "接收到config:oneLineLength:${data[0].oneLineLength},TWO_LINE_LENGTH:${data[0].twoLineLength},INNER_ARC:${data[0].innerArc},OUTER_ARC:${data[0].outerArc},ANGLE:${data[0].angle},".loge(
//                        TAG
//                    )
                }

                else -> {}
            }
            revDataStringBuilder.clear()
        }.onFailure {
            it.printStackTrace()
        }
    }

    /**
     * 初始化EasySocket
     */
    fun initEasySocket(
        homeViewModel: HomeViewModel,
        context: Context,
        listener: SocketStatusListener,
        ip: String,
        port: Int
    ) {
        "设置的socketIp:$ip,port:$port".logd("服务器")
        this.mHomeViewModel = homeViewModel
        //socket配置
        var options = EasySocketOptions.Builder().setSocketAddress(SocketAddress(ip, port))
//            .setReaderProtocol(DefaultMessageProtocol()) //主机地址
            // 强烈建议定义一个消息协议，方便解决 socket黏包、分包的问题
//            .setReaderProtocol(DefaultMessageProtocol()) // 默认的消息协议
            .build()
        //初始化EasySocket
        EasySocket.getInstance().createConnection(options, context)
        //绑定事件
        EasySocket.getInstance().subscribeSocketAction(this)
        mSocketStatusListener = listener

        //发送心跳
        startHeatBeat()/*
           连接上socket之后 如果本地config 数据为空的话，主动向服务器请求config
         */
        sendConfig()
    }


    fun sendSocketData(topic: String, data: Any) {
        val gsonStr =
            GsonUtils.toJson(ToPdaData(arrayListOf(data), 2, TimeUtil.getTimeStamp(), topic))
        EasySocket.getInstance().upMessage("$gsonStr\r\n".toByteArray())
    }


    fun sendTaskData(data4: Data4) {
        sendSocketData("task/end", data4)
    }

    fun sendNoTaskData(data4: Data4) {
//        sendSocketData("task/end/notask", data4)

        sendSocketData("task/end", data4)
    }


    fun close() {
        "socket 心跳结束 进入销毁状态".logd("服务器")
        threadLive = false
        if (mHomeViewModel.socketCommIsConnect.value == true) {
            EasySocket.getInstance().destroyConnection()
        }

//        EasySocket.getInstance().disconnect(false)
//        EasySocket.getInstance().disconnect(true)

    }

//    private var mSocketRespondMsgListener: SocketRespondMsgListener? = null
//    fun addRespondMsg(listener: SocketRespondMsgListener) {
//        mSocketRespondMsgListener = listener
//    }


}